package com.math.aistudykbr.service.impl;

import com.math.aistudykbr.pojo.entity.DocumentChunk;
import com.math.aistudykbr.service.FileParserService;
import com.math.aistudykbr.utils.IntelligentTextSplitter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.pdfbox.multipdf.Splitter;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.poi.xslf.usermodel.*;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class FileParserServiceImpl implements FileParserService {

    private static final int MAX_SLIDE_TEXT_LENGTH = 2000;
    private static final int CHUNK_SIZE = 1500;
    private static final int OVERLAP_SIZE = 200;
    private static final int MAX_PDF_PAGES = 500; // 防止超大文件

    @Override
    public List<DocumentChunk> parseDocument(MultipartFile file) throws Exception {
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        try (InputStream is = file.getInputStream()) {
            return switch (extension.toLowerCase()) {
                case "pdf" -> parsePdf(is);
                case "ppt", "pptx" -> parsePpt(is);
                case "doc" -> parseDoc(is);
                case "docx" -> parseDocx(is);
                default -> throw new IllegalArgumentException("不支持的文件格式: " + extension);
            };
        }
    }

    /**
     * 解析 DOC 文件
     * @param is DOC文件输入流
     * @return 文档块列表
     * @throws IOException 当文件读取失败时抛出
     */
    private List<DocumentChunk> parseDoc(InputStream is) throws IOException {
        try (HWPFDocument doc = new HWPFDocument(is)) {
            WordExtractor extractor = new WordExtractor(doc);
            String text = extractor.getText();
            log.info("提取DOC文件文本，长度：{}", text.length());
            
            // 使用智能文本分割器进行分块
            return IntelligentTextSplitter.splitWithOverlap(text, CHUNK_SIZE, OVERLAP_SIZE);
        }
    }

    /**
     * 解析 DOCX 文件
     * @param is DOCX文件输入流
     * @return 文档块列表
     * @throws IOException 当文件读取失败时抛出
     */
    private List<DocumentChunk> parseDocx(InputStream is) throws IOException {
        try (XWPFDocument doc = new XWPFDocument(is)) {
            StringBuilder content = new StringBuilder();
            
            // 处理段落
            for (XWPFParagraph paragraph : doc.getParagraphs()) {
                content.append(paragraph.getText()).append("\n");
            }
            
            // 处理表格
            for (XWPFTable table : doc.getTables()) {
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        content.append(cell.getText()).append("\t");
                    }
                    content.append("\n");
                }
            }
            
            String text = content.toString();
            log.info("提取DOCX文件文本，长度：{}", text.length());
            
            // 使用智能文本分割器进行分块
            return IntelligentTextSplitter.splitWithOverlap(text, CHUNK_SIZE, OVERLAP_SIZE);
        }
    }

    /**
     * 解析PDF文件
     * @param is
     * @return
     * @throws IOException
     */
    private List<DocumentChunk> parsePdf(InputStream is) throws IOException {
        List<DocumentChunk> documentChunks = new ArrayList<>();

        try (PDDocument document = PDDocument.load(is)) {

            // 初始化PDF解析工具
            PDFTextStripper stripper = new PDFTextStripper();
            stripper.setSortByPosition(true); // 关键优化：按坐标排序文本

            // 分页处理（比循环setStartPage更高效）
            Splitter splitter = new Splitter();
            List<PDDocument> pages = splitter.split(document);

            for (PDDocument page : pages) {
                try (page) { // 自动关闭单页文档
                    String text = stripper.getText(page);
                    log.info("提取第{}页的文本长度：{}", page.getNumberOfPages(), text.length());

                    List<DocumentChunk> pageChunks = IntelligentTextSplitter.splitWithOverlap(
                            text, CHUNK_SIZE, OVERLAP_SIZE
                    );
                    documentChunks.addAll(pageChunks);
                }
            }
        }

        return documentChunks;
    }

    /**
     * 解析PPT文件并生成文档块列表
     * @param is PPT文件输入流
     * @return 分割后的文档块列表
     * @throws IOException 当文件读取失败时抛出
     */
    private List<DocumentChunk> parsePpt(InputStream is) throws IOException {

        // 使用Apache POI的XMLSlideShow解析PPT文件（自动关闭资源）
        try (XMLSlideShow ppt = new XMLSlideShow(is)) {
            List<DocumentChunk> chunks = new ArrayList<>();

            // 遍历PPT中的每一页幻灯片
            for (XSLFSlide slide : ppt.getSlides()) {
                StringBuilder sb = new StringBuilder();

                // 处理幻灯片页面内的所有形状（文本框、表格等）
                for (XSLFShape shape : slide.getShapes()) {
                    processShape(shape, sb);
                }

                // 处理备注
                XSLFNotes notes = slide.getNotes();
                if (notes != null) {
                    for (XSLFShape noteShape : notes.getShapes()) {
                        processShape(noteShape, sb);
                    }
                }

                // 当页面有文本内容时，使用智能文本分割器进行分块处理
                if (!sb.isEmpty()) {
                    chunks.addAll(IntelligentTextSplitter.splitWithOverlap(sb.toString(), MAX_SLIDE_TEXT_LENGTH, 100));
                }
            }
            return chunks;
        }
    }

    /**
     * 递归处理PPT中的形状元素，提取文本内容
     * @param shape PPT形状对象（可以是文本框、表格、组合形状等）
     * @param sb 用于累积文本内容的StringBuilder
     */
    private void processShape(XSLFShape shape, StringBuilder sb) {
        // 处理文本框类型的形状
        if (shape instanceof XSLFTextShape) {
            sb.append(((XSLFTextShape) shape).getText()).append("\n");
        } else if (shape instanceof XSLFTable table) {  // 处理表格类型的形状（逐行逐列提取内容）
            for (XSLFTableRow row : table.getRows()) {
                for (XSLFTableCell cell : row.getCells()) {
                    sb.append(cell.getText()).append("\n");
                }
            }
        } else if (shape instanceof XSLFGroupShape group) { // 处理组合形状（递归处理子形状）
            for (XSLFShape child : group.getShapes()) {
                processShape(child, sb);
            }
        }
    }
}
